home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Pascal / Applications / NIH Image 1.62b11 / src / Edit.p < prev    next >
Text File  |  1996-11-04  |  57KB  |  1,927 lines

  1. unit Edit;
  2.  
  3. {Editing routines used by NIH Image}
  4.  
  5. interface
  6.  
  7.     uses
  8.         Types, Memory, QuickDraw, QuickDrawText, Packages, Menus, Events, Fonts, 
  9.         Scrap, ToolUtils, Resources, Errors, Palettes, StandardFile, Windows,
  10.         Controls, TextEdit, Files, Dialogs, TextUtils, Finder, MixedMode, Processes,
  11.         globals, Utilities, Graphics, Camera, analysis, file1, filters, stacks, Lut, Text, math;
  12.  
  13.  
  14.     procedure FlipOrRotate (DoWhat: FlipRotateType);
  15.     procedure RotateToNewWindow (DoWhat: FlipRotateType);
  16.     procedure Rotate (DoWhat: FlipRotateType);
  17.     procedure DoCopy;
  18.     procedure DoCut;
  19.     procedure DoPaste;
  20.     procedure DoClear;
  21.     procedure ShowClipboard;
  22.     procedure DoObject (obj: ObjectType; event: EventRecord);
  23.     procedure DoSprayCan;
  24.     procedure DoBrush (event: EventRecord);
  25.     procedure DoText (loc: point);
  26.     procedure SetSprayCanSize;
  27.     procedure SetBrushSize;
  28.     procedure SetLineWidth;
  29.     procedure UpdateEditMenu;
  30.     procedure ConverToSystemClipboard;
  31.     procedure ZoomOut;
  32.     procedure ZoomIn (event: EventRecord);
  33.     procedure Scroll (event: EventRecord);
  34.     procedure DoFill (event: EventRecord);
  35.     procedure DoGrow (WhichWindow: WindowPtr; event: EventRecord);
  36.     procedure DrawCharacter (ch: char);
  37.     procedure ConvertFromSystemClipboard;
  38.     procedure SetupOperation (item: integer);
  39.     procedure PastePicture;
  40.     procedure DoUndo;
  41.     procedure FindWhatToCopy;
  42.     procedure CopyResults;
  43.  
  44.  
  45. implementation
  46.  
  47.  
  48.     procedure PivotSelection (var SelectionRect: rect; WindowRect: rect);
  49.         var
  50.             OldWidth, NewWidth, OldHeight, NewHeight, hCenter, vCenter, NewLeft, NewTop: integer;
  51.     begin
  52.         with SelectionRect do begin
  53.                 OldWidth := right - left;
  54.                 OldHeight := bottom - top;
  55.                 hCenter := left + OldWidth div 2;
  56.                 vCenter := top + OldHeight div 2;
  57.             end;
  58.         NewWidth := OldHeight;
  59.         NewHeight := OldWidth;
  60.         NewLeft := hCenter - NewWidth div 2;
  61.         NewTop := vCenter - NewHeight div 2;
  62.         with WindowRect do begin
  63.                 if (NewLeft + NewWidth) > right then
  64.                     NewLeft := right - NewWidth;
  65.                 if (NewTop + NewHeight) > bottom then
  66.                     NewTop := bottom - NewHeight;
  67.                 if NewLeft < 0 then
  68.                     NewLeft := 0;
  69.                 if NewTop < 0 then
  70.                     NewTop := 0;
  71.             end;
  72.         with SelectionRect do begin
  73.                 left := NewLeft;
  74.                 top := NewTop;
  75.                 right := NewLeft + NewWidth;
  76.                 bottom := NewTop + NewHeight;
  77.             end;
  78.     end;
  79.  
  80.  
  81.     procedure FlipLine (var LineBuf: LineType; width: integer);
  82.         var
  83.             TempLine: LineType;
  84.             i, WidthLessOne: integer;
  85.     begin
  86.         TempLine := LineBuf;
  87.         WidthLessOne := width - 1;
  88.         for i := 0 to width - 1 do
  89.             LineBuf[i] := TempLine[WidthLessOne - i];
  90.     end;
  91.  
  92.  
  93.     procedure ScreenToOffscreenRect (var r: rect);
  94.         var
  95.             p1, p2: point;
  96.     begin
  97.         with r do begin
  98.                 p1.h := left;
  99.                 p1.v := top;
  100.                 p2.h := right;
  101.                 p2.v := bottom;
  102.                 ScreenToOffscreen(p1);
  103.                 ScreenToOffscreen(p2);
  104.                 Pt2Rect(p1, p2, r);
  105.             end;
  106.     end;
  107.  
  108.  
  109.     procedure FlipOrRotate (DoWhat: FlipRotateType);
  110.         var
  111.             SaveInfo: InfoPtr;
  112.             width, height, hDst, vSrc, vDst, hSrc, i, inc: integer;
  113.             LineBuf: LineType;
  114.             srect, drect, MaskRect: rect;
  115.             AutoSelectAll: boolean;
  116.             SaveRow:integer;
  117.             NextUpdate: LongInt;
  118.  
  119.     begin
  120.         if NotRectangular or NotInBounds or NoUndo then
  121.             exit(FlipOrRotate);
  122.         AutoSelectAll := not Info^.RoiShowing;
  123.         if AutoSelectAll then
  124.             SelectAll(true);
  125.         if TooWide then
  126.             exit(FlipOrRotate);
  127.         ShowWatch;
  128.         SetupUndoFromClip;
  129.         SetupUndo;
  130.         if (DoWhat = RotateLeft) or (DoWhat = RotateRight) then
  131.             WhatToUndo := UndoRotate
  132.         else
  133.             WhatToUndo := UndoFlip;
  134.         SetupUndoInfoRec;
  135.         SaveInfo := Info;
  136.         srect := info^.RoiRect;
  137.         case DoWhat of
  138.  
  139.             RotateLeft, RotateRight: 
  140.                 with srect do begin
  141.                         if OptionKeyWasDown then
  142.                             DoOperation(EraseOp);
  143.                         drect := srect;
  144.                         with info^ do begin
  145.                                 PivotSelection(drect, PicRect);
  146.                                 MaskRect := drect;
  147.                                 RoiRect := drect;
  148.                                 RectRgn(roiRgn, RoiRect);
  149.                             end;
  150.                         width := right - left;
  151.                         if DoWhat = RotateLeft then begin
  152.                                 hDst := drect.left;
  153.                                 inc := 1
  154.                             end
  155.                         else begin
  156.                                 hDst := drect.right - 1;
  157.                                 inc := -1
  158.                             end;
  159.                         SaveRow:=top;
  160.                         NextUpdate:=TickCount+6; {10/sec}
  161.                         for vSrc := top to bottom - 1 do begin
  162.                                 Info := UndoInfo;
  163.                                 GetLine(left, vSrc, width, LineBuf);
  164.                                 if DoWhat = RotateLeft then
  165.                                     FlipLine(LineBuf, width);
  166.                                 Info := SaveInfo;
  167.                                 PutColumn(hDst, drect.top, width, LineBuf);
  168.                                 hDst := hDst + inc;
  169.                                 if TickCount>=NextUpdate then begin
  170.                                     SetRect(MaskRect, left, SaveRow, left+width, vSrc + 1);
  171.                                     UpdateScreen(MaskRect);
  172.                                     SaveRow:=vSrc+1;
  173.                                     NextUpdate:=TickCount+6;
  174.                                     ShowAnimatedWatch;
  175.                                 end;
  176.                             end;
  177.                             SetRect(MaskRect, left, SaveRow, left+width, bottom);
  178.                             UpdateScreen(MaskRect);
  179.                     end;
  180.  
  181.             FlipVertical: 
  182.                 with srect do begin
  183.                         width := right - left;
  184.                         vDst := bottom;
  185.                         for vSrc := top to bottom - 1 do begin
  186.                                 Info := UndoInfo;
  187.                                 GetLine(left, vSrc, width, LineBuf);
  188.                                 Info := SaveInfo;
  189.                                 vDst := vDst - 1;
  190.                                 PutLine(left, vDst, width, LineBuf);
  191.                             end;
  192.                     end;
  193.  
  194.             FlipHorizontal: 
  195.                 with srect do begin
  196.                         width := right - left;
  197.                         SaveRow:=top;
  198.                         NextUpdate:=TickCount+6; {10/sec}
  199.                         for vSrc := top to bottom - 1 do begin
  200.                                 Info := UndoInfo;
  201.                                 GetLine(left, vSrc, width, LineBuf);
  202.                                 FlipLine(LineBuf, width);
  203.                                 Info := SaveInfo;
  204.                                 PutLine(left, vSrc, width, LineBuf);
  205.                                 if TickCount>=NextUpdate then begin
  206.                                     SetRect(MaskRect, left, SaveRow, left+width, vSrc + 1);
  207.                                     UpdateScreen(MaskRect);
  208.                                     SaveRow:=vSrc+1;
  209.                                     NextUpdate:=TickCount+6;
  210.                                     ShowAnimatedWatch;
  211.                                 end;
  212.                             end;
  213.                             SetRect(MaskRect, left, SaveRow, left+width, bottom);
  214.                             UpdateScreen(MaskRect);
  215.                     end;
  216.  
  217.         end; {case}
  218.         Info := SaveInfo;
  219.         Info^.changes := true;
  220.         SetupRoiRect;
  221.         if AutoSelectAll then
  222.             KillRoi;
  223.     end;
  224.  
  225.  
  226.  
  227.     procedure RotateToNewWindow (DoWhat: FlipRotateType);
  228.         var
  229.             SrcInfo, DstInfo: InfoPtr;
  230.             Srcwidth, DstWidth, DstHeight, hDst, vSrc, vDst, hSrc, i, inc, ignore: integer;
  231.             LineBuf: LineType;
  232.             SourceRect, DstRect, MaskRect: rect;
  233.             AutoSelectAll, isStack: boolean;
  234.             SaveCol:integer;
  235.             NextUpdate: LongInt;
  236.     begin
  237.         if NotRectangular or NotInBounds then
  238.             exit(RotateToNewWindow);
  239.         AutoSelectAll := not Info^.RoiShowing;
  240.         isStack := info^.StackInfo <> nil;
  241.         if AutoSelectAll then
  242.             SelectAll(true);
  243.         if TooWide then
  244.             exit(RotateToNewWindow);
  245.         ShowWatch;
  246.         SrcInfo := info;
  247.         with info^, info^.RoiRect do begin
  248.                 SourceRect := RoiRect;
  249.                 SrcWidth := right - left;
  250.                 DstWidth := bottom - top;
  251.                 DstHeight := right - left;
  252.                 if not NewPicWindow(title, DstWidth, DstHeight) then begin
  253.                         KillRoi;
  254.                         AbortMacro;
  255.                         exit(RotateToNewWindow)
  256.                     end;
  257.                 DstInfo := info;
  258.                 DstRect := info^.PicRect;
  259.             end;
  260.         if DoWhat = RotateLeft then begin
  261.                 hDst := 0;
  262.                 inc := 1
  263.             end
  264.         else begin
  265.                 hDst := DstWidth - 1;
  266.                 inc := -1
  267.             end;
  268.         with SourceRect do begin
  269.             SaveCol:=hDst;
  270.             NextUpdate:=TickCount+6; {10/sec}
  271.             for vSrc := top to bottom - 1 do begin
  272.                     Info := SrcInfo;
  273.                     GetLine(left, vSrc, SrcWidth, LineBuf);
  274.                     if DoWhat = RotateLeft then
  275.                         FlipLine(LineBuf, SrcWidth);
  276.                     Info := DstInfo;
  277.                     PutColumn(hDst, 0, SrcWidth, LineBuf);
  278.                     if TickCount>=NextUpdate then begin
  279.                         if DoWhat=RotateLeft
  280.                             then SetRect(MaskRect, SaveCol, 0, hDst+1, SrcWidth)
  281.                             else SetRect(MaskRect, hDst, 0, SaveCol+1, SrcWidth);
  282.                         UpdateScreen(MaskRect);
  283.                         SaveCol:=hDst+1;
  284.                         NextUpdate:=TickCount+6;
  285.                         ShowAnimatedWatch;
  286.                     end;
  287.                     hDst := hDst + inc;
  288.                 end; {for}
  289.                 if DoWhat=RotateLeft
  290.                     then SetRect(MaskRect, SaveCol, 0, dstWidth, SrcWidth)
  291.                     else SetRect(MaskRect, 0, 0, SaveCol+1, SrcWidth);
  292.                 UpdateScreen(MaskRect);
  293.             end; {with}
  294.         info^.changes := true;
  295.         if AutoSelectAll and not isStack then
  296.             with SrcInfo^ do begin
  297.                     Changes := false;
  298.                     ignore := CloseAWindow(wptr);
  299.                     info := DstInfo;
  300.                 end;
  301.     end;
  302.  
  303.  
  304.     procedure Rotate; {(DoWhat: FlipRotateType)}
  305.         const
  306.             NewWindowID = 3;
  307.         var
  308.             mylog: DialogPtr;
  309.             item: integer;
  310.             NewWindow: boolean;
  311.     begin
  312.         with info^, info^.RoiRect do
  313.             if RoiShowing then
  314.                 NewWindow := ((right - left) > PicRect.bottom) or ((bottom - top) > PicRect.right)
  315.             else begin
  316.                     RotateToNewWindow(DoWhat);
  317.                     exit(Rotate);
  318.                 end;
  319.         InitCursor;
  320.         mylog := GetNewDialog(120, nil, pointer(-1));
  321.         SetDlogItem(mylog, NewWindowID, ord(NewWindow));
  322.         OutlineButton(MyLog, ok, 16);
  323.         repeat
  324.             if item = NewWindowID then begin
  325.                     NewWindow := not NewWindow;
  326.                     SetDlogItem(mylog, NewWindowID, ord(NewWindow));
  327.                 end;
  328.             ModalDialog(nil, item);
  329.         until (item = ok) or (item = cancel);
  330.         DisposeDialog(mylog);
  331.         if item = cancel then
  332.             exit(Rotate);
  333.         if NewWindow then
  334.             RotateToNewWindow(DoWhat)
  335.         else
  336.             FlipOrRotate(DoWhat);
  337.     end;
  338.  
  339.  
  340.     function CopyImage: boolean;
  341.         var
  342.             err, width, EvenWidth, height, size: LongInt;
  343.             line: integer;
  344.             ClipXOffset, ClipYOffset: integer;
  345.             SavePort: GrafPtr;
  346.             SaveGDevice: GDHandle;
  347.     begin
  348.         if OpPending then begin
  349.             KillRoi;
  350.             RestoreRoi;
  351.         end;
  352.         with info^, info^.RoiRect do begin
  353.             if (RoiType = RectRoi) and (PictureType = FrameGrabberType) then begin
  354.                 {We can't offset an roi copied from Camera window or "live" paste won't work}
  355.                 ClipXOffset := 0;
  356.                 ClipYOffset := 0;
  357.                 width := picRect.right;
  358.                 height := picRect.bottom;
  359.             end else begin
  360.                 ClipXOffset := left;
  361.                 ClipYOffset := top;
  362.                 width := right - left;
  363.                 height := bottom - top;
  364.             end;
  365.             if odd(width) then
  366.                 EvenWidth := width + 1
  367.             else
  368.                 EvenWidth := width;
  369.             size := EvenWidth * height;
  370.             if size > ClipBufSize then begin
  371.                 PutError(StringOf('This ',size div 1024:1,'K selection is larger than the ',ClipBufSize div 1024:1,'K Clipboard buffer.'));
  372.                 WhatsOnClip := NothingOnClip;
  373.                 AbortMacro;
  374.                 CopyImage := false;
  375.                 exit(CopyImage)
  376.             end;
  377.         end;
  378.         with ClipBufInfo^ do begin
  379.             PixelsPerLine := width;
  380.             BytesPerRow := EvenWidth;
  381.             nLines := height;
  382.             RoiRect := info^.RoiRect;
  383.             OffsetRect(RoiRect, -ClipXOffset, -ClipYOffset);
  384.             roiType := Info^.roiType;
  385.             PicRect := RoiRect;
  386.             with osPort^.portPixMap^^ do begin
  387.                     RowBytes := BitOr(BytesPerRow, $8000);
  388.                     bounds := PicRect;
  389.                 end;
  390.             with osPort^ do begin
  391.                     PortRect := PicRect;
  392.                     RectRgn(visRgn, PicRect);
  393.                 end;
  394.             if RoiType = RectRoi then begin
  395.                 if info^.PictureType = FrameGrabberType then
  396.                     WhatsOnClip := CameraPic
  397.                 else
  398.                     WhatsOnClip := RectPic
  399.             end else
  400.                 WhatsOnClip := NonRectPic;
  401.             SaveGDevice := GetGDevice;
  402.             SetGDevice(osGDevice);
  403.             GetPort(SavePort);
  404.             SetPort(GrafPtr(osPort));
  405.             CopyRgn(info^.roiRgn, roiRgn);
  406.             OffsetRgn(roiRgn, -ClipXOffset, -ClipYOffset);
  407.             ctable := info^.ctable;
  408.             pmForeColor(BlackIndex);
  409.             pmBackColor(WhiteIndex);
  410.             CopyBits(BitMapHandle(Info^.osPort^.portPixMap)^^, BitMapHandle(osPort^.PortPixMap)^^, Info^.RoiRect, RoiRect, SrcCopy, nil);
  411.             pmForeColor(ForegroundIndex);
  412.             pmBackColor(BackgroundIndex);
  413.             SetPort(SavePort);
  414.             SetGDevice(SaveGDevice);
  415.         end; {with}
  416.         CopyImage := true;
  417.     end;
  418.  
  419.  
  420.     procedure CopyWindow;
  421.         var
  422.             tPort: GrafPtr;
  423.             WindowSize: LongInt;
  424.             WindowRect: rect;
  425.             WhichWindow: WindowPtr;
  426.             kind, ignore: integer;
  427.             HidingPasteControl: boolean;
  428.             SaveGDevice: GDHandle;i:integer;
  429.     begin
  430.         WhichWindow := FrontWindow;
  431.         if WhichWindow = nil then
  432.             exit(CopyWindow);
  433.         WindowRect := WhichWindow^.PortRect;
  434.         kind := WindowPeek(WhichWindow)^.WindowKind;
  435.         HidingPasteControl := false;
  436.         with WindowRect do begin
  437.                 WindowSize := right;
  438.                 WindowSize := WindowSize * bottom;
  439.             end;
  440.         if kind = LUTKind then
  441.             WindowRect.bottom := 256;
  442.         case kind of
  443.             ProfilePlotKind:  begin
  444.                     ConvertPlotToText;
  445.                     ClipTextInBuffer := true;
  446.                 end;
  447.             CalibrationPlotKind:  begin
  448.                     ConvertCalibrationCurveToText;
  449.                     ClipTextInBuffer := true;
  450.                 end;
  451.             HistoKind, LUTKind, MapKind, ToolKind:  begin
  452.                     if PasteControl <> nil then begin
  453.                             ignore := CloseAWindow(PasteControl);
  454.                             HidingPasteControl := true;
  455.                         end;
  456.                     case kind of
  457.                         HistoKind:  begin
  458.                                 ConvertHistoToText;
  459.                                 ClipTextInBuffer := true;
  460.                                 DrawHistogram;
  461.                             end;
  462.                         MapKind: 
  463.                             DrawMap;
  464.                         LUTKind: 
  465.                             DrawLUT;
  466.                         ToolKind: 
  467.                             DrawTools;
  468.                     end; {case}
  469.                 end;
  470.             otherwise
  471.         end; {case}
  472.         if NoUndo then begin
  473.                 WhatsOnClip := NothingOnClip;
  474.                 exit(CopyWindow)
  475.             end;
  476.         ClipboardConverted := false;
  477.         with ClipBufInfo^ do begin
  478.                 RoiType := RectRoi;
  479.                 RoiRect := WindowRect;
  480.                 RectRgn(roiRgn, RoiRect);
  481.                 PicRect := WindowRect;
  482.                 PixelsPerLine := WindowRect.right;
  483.                 BytesPerRow := PixelsPerLine;
  484.                 if odd(BytesPerRow) then
  485.                     BytesPerRow := BytesPerRow + 1;
  486.                 nLines := WindowRect.bottom;
  487.                 with osPort^.portPixMap^^ do begin
  488.                         RowBytes := BitOr(BytesPerRow, $8000);
  489.                         bounds := WindowRect;
  490.                     end;
  491.                 with osPort^ do begin
  492.                         PortRect := PicRect;
  493.                         RectRgn(visRgn, PicRect);
  494.                         SetRectRgn(ClipRgn, 0, 0, 30000, 30000);
  495.                     end;
  496.                 WhatsOnClip := RectPic;
  497.                 SaveGDevice := GetGDevice;
  498.                 SetGDevice(osGDevice);
  499.                 GetPort(tPort);
  500.                 SetPort(GrafPtr(osPort));
  501.                 RGBForeColor(BlackRGB);
  502.                 RGBBackColor(WhiteRGB);
  503.                 if (kind = ProfilePlotKind) or (kind = CalibrationPlotKind) then begin
  504.                         EraseRect(osPort^.portRect);
  505.                         DrawPlot
  506.                     end
  507.                 else
  508.                     CopyBits(WhichWindow^.PortBits, BitMapHandle(osPort^.portPixMap)^^, WindowRect, WindowRect, SrcCopy, nil);
  509.                 SetPort(tPort);
  510.                 SetGDevice(SaveGDevice);
  511.             end; {with}
  512.         if HidingPasteControl then
  513.             ShowPasteControl;
  514.     end;
  515.  
  516.  
  517.     procedure CopyResults;
  518.         var
  519.             err: OSErr;
  520.     begin
  521.         CopyResultsToBuffer(1, mCount, ShowHeadings);
  522.         UnsavedResults := false;
  523.         err := ZeroScrap;
  524.         if err = NoErr then begin
  525.                 err := PutScrap(TextBufSize, 'TEXT', ptr(TextBufP));
  526.                 WhatsOnClip := NothingOnClip; {The text is on the System Scrap}
  527.             end;
  528.     end;
  529.  
  530.  
  531.     procedure DoCopy;
  532.         var
  533.             err: OSErr;
  534.     begin
  535.         err := ZeroScrap;
  536.         OldScrapCount := GetScrapCount;
  537.         case WhatToCopy of
  538.             CopyColor: 
  539.                 DoCopyColor;
  540.             CopySelection:  begin
  541.                     if not CopyImage then exit(DoCopy);
  542.                     ClipTextInBuffer := false;
  543.                     ClipboardConverted := false;
  544.                 end;
  545.             CopyHistogram, CopyPlot, CopyCalibrationPlot, CopyCLUT, CopyGrayMap, CopyTools: 
  546.                 CopyWindow;
  547.             CopyMeasurements: 
  548.                 CopyResults;
  549.             CopyText: 
  550.                 DoTextCopy;
  551.             otherwise
  552.                 beep;
  553.         end;
  554.     end;
  555.  
  556.  
  557.     procedure DoCut;
  558.     begin
  559.         DoCopy;
  560.         DoClear;
  561.     end;
  562.  
  563.  
  564.     procedure CenterRect (inRect, outRect: rect; var ResultRect: rect);
  565. {Creates a new rectangle(ResultsRect) that is the same size as inRect, but centered within outRect.}
  566.         var
  567.             width, height, hcenter, vcenter: integer;
  568.     begin
  569.         with inRect do begin
  570.                 width := right - left;
  571.                 height := bottom - top;
  572.             end;
  573.         with outRect do begin
  574.                 hcenter := left + (right - left) div 2;
  575.                 vcenter := top + (bottom - top) div 2;
  576.             end;
  577.         with ResultRect do begin
  578.                 left := hcenter - width div 2;
  579.                 top := vcenter - height div 2;
  580.                 right := left + width;
  581.                 bottom := top + height;
  582.             end;
  583.     end;
  584.  
  585.  
  586.     procedure PastePicture;
  587.         var
  588.             loc: point;
  589.             SrcWidth, SrcHeight, DstHeight, DstWidth, dh, dv: integer;
  590.             DestRect: rect;
  591.             WindowNotResized: boolean;
  592.     begin
  593.         if LivePasteMode or (PasteTransferMode <> SrcCopy) then begin
  594.                 LivePasteMode := false;
  595.                 PasteTransferMode := SrcCopy;
  596.                 if PasteControl <> nil then
  597.                     DrawPasteControl
  598.             end;
  599.         with info^ do begin
  600.                 SetupUndo;
  601.                 WhatToUndo := UndoPaste;
  602.                 if RoiShowing then
  603.                     with RoiRect do {Pasting back into selection of same size?}
  604.                         if ((right - left) = (ClipBufInfo^.RoiRect.right - ClipBufInfo^.RoiRect.left)) and ((bottom - top) = (ClipBufInfo^.RoiRect.bottom - ClipBufInfo^.RoiRect.top)) and (ClipBufInfo^.RoiType = RoiType) then begin
  605.                                 OpPending := true;
  606.                                 CurrentOp := PasteOp;
  607.                                 exit(PastePicture)
  608.                             end;
  609.                 with ClipBufInfo^.RoiRect do {Pasting into same size window?}
  610.                     if (PicRect.right = right - left) and (PicRect.bottom = (bottom - top)) and (ClipBufInfo^.RoiType = RectRoi) then begin
  611.                             SelectAll(true);
  612.                             WhatToUndo := UndoPaste;
  613.                             OpPending := true;
  614.                             CurrentOp := PasteOp;
  615.                             exit(PastePicture)
  616.                         end;
  617.                 if RoiShowing or (roiType <> NoRoi) then
  618.                     KillRoi;
  619.                 with ClipBufInfo^.RoiRect do begin
  620.                         SrcWidth := right - left;
  621.                         SrcHeight := bottom - top;
  622.                     end;
  623.                 with SrcRect do begin
  624.                         DstWidth := right - left;
  625.                         DstHeight := bottom - top;
  626.                     end;
  627.                 with initwrect do
  628.                     WindowNotResized := (DstWidth = (right - left)) and (DstHeight = (bottom - top));
  629.                 if ((SrcWidth > DstWidth) or (SrcHeight > DstHeight)) and WindowNotResized then
  630.                     DestRect := PicRect
  631.                 else
  632.                     DestRect := SrcRect;
  633.                 CenterRect(ClipBufInfo^.RoiRect, DestRect, RoiRect);
  634.                 roiType := ClipBufInfo^.roiType;
  635.                 CopyRgn(ClipBufInfo^.roiRgn, roiRgn);
  636.                 dh := RoiRect.left - roiRgn^^.rgnbbox.left;
  637.                 dv := RoiRect.top - roiRgn^^.rgnbbox.top;
  638.                 OffsetRgn(roiRgn, dh, dv);
  639.                 RoiShowing := true;
  640.                 OpPending := true;
  641.                 CurrentOp := PasteOp;
  642.                 BinaryPic := false;
  643.             end;{with}
  644.     end;
  645.  
  646.  
  647.     procedure ConvertFromSystemClipboard;
  648.   {Converts system-wide clipboard to local clipboard.}
  649.     var
  650.         phandle: handle;
  651.         offset, length, size, EvenWidth: LongInt;
  652.         pframe: rect;
  653.         width, height: LongInt;
  654.         tPort: GrafPtr;
  655.         ScrapInfo: ScrapStuffPtr;
  656.         SaveGDevice: GDHandle;
  657.     begin
  658.         ScrapInfo := InfoScrap;
  659.         if ScrapInfo^.ScrapSize <= 0 then
  660.             exit(ConvertFromSystemClipboard);
  661.         phandle := NewHandle(0);
  662.         length := GetScrap(phandle, 'PICT', offset);
  663.         if length > 0 then begin
  664.             ShowWatch;
  665.             pframe := PicHandle(phandle)^^.PicFrame;
  666.             with pframe do begin
  667.                 width := right - left;
  668.                 if odd(width) then
  669.                     EvenWidth := width + 1
  670.                 else
  671.                     EvenWidth := width;
  672.                 height := bottom - top;
  673.                 size := EvenWidth * height;
  674.                 if size > ClipBufSize then begin
  675.                     PutError(StringOf('The ', size div 1024:1,'K image on the system clipboard is too large to paste.'));
  676.                     DisposeHandle(phandle);
  677.                     exit(ConvertFromSystemClipboard)
  678.                 end;
  679.             end;
  680.             with ClipBufInfo^ do begin
  681.                 PixelsPerLine := width;
  682.                 nlines := height;
  683.                 SetRect(PicRect, 0, 0, width, height);
  684.                 RoiRect := PicRect;
  685.                 RoiType := RectRoi;
  686.                 SaveGDevice := GetGDevice;
  687.                 SetGDevice(osGDevice);
  688.                 GetPort(tPort);
  689.                 SetPort(GrafPtr(osPif WhatsOnClip = textOnClip then
  690.                         PasteText
  691.                     else
  692.                         beep;
  693.                 end;
  694.         end;
  695.     end;
  696.  
  697.  
  698.     procedure DoClear;
  699.         var
  700.             fwptr: WindowPtr;
  701.             kind: integer;
  702.     begin
  703.         fwptr := FrontWindow;
  704.         if fwptr = nil then
  705.             exit(DoClear);
  706.         kind := WindowPeek(fwptr)^.WindowKind;
  707.         if Kind = TextKind then begin
  708.                 DoTextClear;
  709.                 exit(DoClear);
  710.             end;
  711.         if not NoSelection then begin
  712.                 SetupUndo;
  713.                 WhatToUndo := UndoClear;
  714.                 CurrentOp := EraseOp;
  715.                 OpPending := true;
  716.                 RoiUpdateTime := 0;
  717.             end;
  718.     end;
  719.  
  720.  
  721.     procedure ShowClipboard;
  722.         var
  723.             width, height, hstart, vstart, i, NewScrapCount: integer;
  724.             okay:boolean;
  725.     begin
  726.         NewScrapCount := GetScrapCount;
  727.         if NewScrapCount <> OldScrapCount then begin
  728.                 WhatsOnClip := NothingOnClip;
  729.                 OldScrapCount := NewScrapCount;
  730.             end;
  731.         if WhatsOnClip = NothingOnClip then
  732.             ConvertFromSystemClipboard;
  733.         if (WhatsOnClip = RectPic) or (WhatsOnClip = NonRectPic) or (WhatsOnClip = ImportedPic) or (WhatsOnClip = CameraPic) then
  734.             with ClipBufinfo^.RoiRect do begin
  735.                     width := right - left;
  736.                     height := bottom - top;
  737.                     if NewPicWindow('Clipboard', width, height) then begin
  738.                             PastePicture;
  739.                             KillRoi;
  740.                             SetupUndo;
  741.                             info^.changes := false;
  742.                         end;
  743.                 end;
  744.         if WhatsOnClip = TextOnClip then begin
  745.             if MakeNewTextWindow('Clipboard', 400, 350) then
  746.                 DoTextPaste; 
  747.         end;
  748.     end;
  749.  
  750.  
  751.     function ScreenToPixmapH (hloc: integer): extended;
  752.     begin
  753.         with info^ do
  754.             ScreenToPixmapH := SrcRect.left + hloc / magnification;
  755.     end;
  756.  
  757.     function ScreenToPixmapV (vloc: integer): extended;
  758.     begin
  759.         with info^ do
  760.             ScreenToPixmapV := SrcRect.top + vloc / magnification;
  761.     end;
  762.  
  763.  
  764.     procedure DoSelection (obj: ObjectType; start, finish: point);
  765.         var
  766.             tRect: rect;
  767.             temp, StartH, StartV, FinishH, FinishV: integer;
  768.             TempRgn: RgnHandle;
  769.     begin
  770.         WhatToUndo := NothingToUndo;
  771.         Info^.RoiShowing := false;
  772.         RoiUpdateTime := 0;
  773.         if (start.h = finish.h) or (start.v = finish.v) then
  774.             exit(DoSelection);
  775.         if start.h > finish.h then begin
  776.                 temp := start.h;
  777.                 start.h := finish.h;
  778.                 finish.h := temp;
  779.             end;
  780.         if start.v > finish.v then begin
  781.                 temp := start.v;
  782.                 start.v := finish.v;
  783.                 finish.v := temp;
  784.             end;
  785.         StartH := round(ScreenToPixmapH(start.h));
  786.         StartV := round(ScreenToPixmapV(start.v));
  787.         FinishH := round(ScreenToPixmapH(finish.h));
  788.         FinishV := round(ScreenToPixmapV(finish.v));
  789.         SetRect(tRect, StartH, StartV, FinishH, FinishV);
  790.         with info^ do begin
  791.                 RoiShowing := true;
  792.                 if SelectionMode <> NewSelection then
  793.                     TempRgn := NewRgn;
  794.                 OpenRgn;
  795.                 case obj of
  796.                     SelectionOval:  begin
  797.                             FrameOval(tRect);
  798.                             roiType := OvalRoi;
  799.                         end;
  800.                     SelectionRect:  begin
  801.                             FrameRect(tRect);
  802.                             roiType := RectRoi;
  803.                         end;
  804.                 end;
  805.                 if SelectionMode = NewSelection then
  806.                     CloseRgn(roiRgn)
  807.                 else begin
  808.                         CloseRgn(TempRgn);
  809.                         if RgnNotTooBig(roiRgn, TempRgn) then begin
  810.                                 if SelectionMode = AddSelection then
  811.                                     UnionRgn(roiRgn, TempRgn, roiRgn)
  812.                                 else begin
  813.                                         DiffRgn(roiRgn, TempRgn, roiRgn);
  814.                                         UpdatePicWindow;
  815.                                     end;
  816.                             end;
  817.                         DisposeRgn(TempRgn);
  818.                         if GetHandleSize(handle(roiRgn)) = 10 then
  819.                             roiType := RectRoi
  820.                         else
  821.                             roiType := FreehandRoi;
  822.                         nCoordinates := 0;
  823.                     end;
  824.                 RoiRect := roiRgn^^.rgnBBox;
  825.             end;{with}
  826.         measuring := false;
  827.     end;
  828.  
  829.  
  830.     procedure DoObject; {(obj: ObjectType; event: EventRecord)}
  831.         var
  832.             Start, Finish, ScreenStart, ScreenFinish, osStart, osFinish: point;
  833.             r: rect;
  834.             DeltaX, DeltaY, switch: integer;
  835.             Constrain: boolean;
  836.             StartH, StartV: extended;
  837.     begin
  838.         SetPort(info^.wptr);
  839.         if obj = LineObj then
  840.             DrawLabels('DX:', 'DY:', 'Length:')
  841.         else
  842.             DrawLabels('Width:', 'Height:', '');
  843.         start := event.where;
  844.         StartH := ScreenToPixmapH(start.h);
  845.         StartV := ScreenToPixmapV(start.v);
  846.         osStart := start;
  847.         ScreenToOffscreen(osStart);
  848.         finish := start;
  849.         osFinish := finish;
  850.         ScreenToOffscreen(osFinish);
  851.         PenNormal;
  852.         PenMode(PatXor);
  853.         PenSize(1, 1);
  854.         while button do begin
  855.                 GetMouse(finish);
  856.                 with finish, Info^ do begin
  857.                         if h > wrect.right then
  858.                             h := wrect.right;
  859.                         if v > wrect.bottom then
  860.                             v := wrect.bottom;
  861.                         if h < 0 then
  862.                             h := 0;
  863.                         if v < 0 then
  864.                             v := 0;
  865.                     end;
  866.                 if ShiftKeyDown then begin
  867.                         DeltaX := finish.h - start.h;
  868.                         DeltaY := finish.v - start.v;
  869.                         if obj = lineObj then begin
  870.                                 if abs(DeltaX) > abs(DeltaY) then
  871.                                     finish.v := start.v
  872.                                 else
  873.                                     finish.h := start.h
  874.                             end
  875.                         else begin
  876.                                 if ((DeltaX > 0) and (DeltaY < 0)) or ((DeltaX < 0) and (DeltaY > 0)) then
  877.                                     switch := -1
  878.                                 else
  879.                                     switch := 1;
  880.                                 if abs(DeltaX) > abs(DeltaY) then
  881.                                     finish.h := start.h + switch * DeltaY
  882.                                 else
  883.                                     finish.v := start.v + switch * DeltaX;
  884.                             end;
  885.                     end;
  886.                 osFinish := finish;
  887.                 ScreenToOffscreen(osfinish);
  888.                 case obj of
  889.                     LineObj:  begin
  890.                             MoveTo(start.h, start.v);
  891.                             LineTo(finish.h, finish.v);
  892.                             ShowDxDy(abs(ScreenToPixMapH(finish.h) - StartH), abs(ScreenToPixMapV(finish.v) - StartV));
  893.                             MoveTo(start.h, start.v);
  894.                             LineTo(finish.h, finish.v);
  895.                         end;
  896.                     Rectangle, SelectionRect:  begin
  897.                             if obj = SelectionRect then begin
  898.                                     PatIndex := (PatIndex + 1) mod 8;
  899.                                     PenPat(AntPattern[PatIndex]);
  900.                                 end;
  901.                             Pt2Rect(start, finish, r);
  902.                             FrameRect(r);
  903.                             Show3Values(osfinish.h - osstart.h, osfinish.v - osstart.v, -1);
  904.                             Pt2Rect(start, finish, r);
  905.                             FrameRect(r);
  906.                         end;
  907.                     SelectionOval:  begin
  908.                             PatIndex := (PatIndex + 1) mod 8;
  909.                             PenPat(AntPattern[PatIndex]);
  910.                             Pt2Rect(start, finish, r);
  911.                             FrameOval(r);
  912.                             Show3Values(osfinish.h - osstart.h, osfinish.v - osstart.v, -1);
  913.                             Pt2Rect(start, finish, r);
  914.                             FrameOval(r);
  915.                         end;
  916.                 end; {case}
  917.             end;  {while button}
  918.         if (obj = SelectionRect) or (obj = SelectionOval) then begin
  919.                 DoSelection(obj, start, finish);
  920.                 exit(DoObject);
  921.             end;
  922.         if (obj = LineObj) and ((CurrentTool = LineTool) or (CurrentTool = PlotTool)) then begin
  923.                 MoveTo(start.h, start.v);
  924.                 LineTo(finish.h, finish.v);
  925.                 with info^ do begin
  926.                         LX1 := StartH;
  927.                         LY1 := StartV;
  928.                         LX2 := ScreenToPixmapH(finish.h);
  929.                         LY2 := ScreenToPixmapV(finish.v);
  930.                         if LX1 > (PicRect.right - 1) then
  931.                             LX1 := PicRect.right - 1;
  932.                         if LY1 > (PicRect.bottom - 1) then
  933.                             LY1 := PicRect.bottom - 1;
  934.                         if LX1 < 0 then
  935.                             LX1 := 0;
  936.                         if LY1 < 0 then
  937.                             LY1 := 0;
  938.                         if LX2 > (PicRect.right - 1) then
  939.                             LX2 := PicRect.right - 1;
  940.                         if LY2 > (PicRect.bottom - 1) then
  941.                             LY2 := PicRect.bottom - 1;
  942.                         if LX2 < 0 then
  943.                             LX2 := 0;
  944.                         if LY2 < 0 then
  945.                             LY2 := 0;
  946.                     end;
  947.                 exit(DoObject);
  948.             end;
  949.         DrawObject(obj, start, finish);
  950.     end;
  951.  
  952.  
  953.     procedure DrawSprayCan (xcenter, ycenter: integer);
  954.         var
  955.             i, xoffset, yoffset, nDots: LongInt;
  956.     begin
  957.         nDots := SprayCanDiameter div 4;
  958.         if nDots < 15 then
  959.             nDots := 15;
  960.         for i := 1 to nDots do begin
  961.                 repeat
  962.                     xoffset := random mod SprayCanRadius;
  963.                     yoffset := random mod SprayCanRadius;
  964.                 until xoffset * xoffset + yoffset * yoffset <= SprayCanRadius2;
  965.                 PutPixel(xcenter + xoffset, ycenter + yoffset, ForegroundIndex);
  966.             end;
  967.     end;
  968.  
  969.  
  970.     procedure DoSprayCan;
  971.   {Reference: "Spaying and Smudging", Dick Pountain, Byte, November 1987}
  972.         var
  973.             xcenter, ycenter, off: integer;
  974.             MaskRect: rect;
  975.             pt: point;
  976.             SaveTicks:LongInt;
  977.     begin
  978.         info^.changes := true;
  979.         off := SprayCanRadius;
  980.         SaveTicks:=TickCount;
  981.         repeat
  982.             repeat until TickCount<>SaveTicks; {Update no more than 60 times per second}
  983.             SaveTicks:=TickCount;
  984.             GetMouse(pt);
  985.             ScreenToOffscreen(pt);
  986.             with MaskRect, pt do begin
  987.                     left := h - off;
  988.                     top := v - off;
  989.                     right := h + off;
  990.                     bottom := v + off;
  991.                 end;
  992.             with pt do begin
  993.                     xcenter := h;
  994.                     ycenter := v
  995.                 end;
  996.             DrawSprayCan(xcenter, ycenter);
  997.             UpdateScreen(MaskRect);
  998.         until not button;
  999.         WhatToUndo := UndoEdit;
  1000.     end;
  1001.  
  1002.  
  1003.     procedure DoBrush; {(event: EventRecord)}
  1004.         var
  1005.             r, ScreenRect: rect;
  1006.             p1, p2, p2x, start: point;
  1007.             WhichWindow: WindowPtr;
  1008.             SaveLineWidth, SaveForegroundColor: integer;
  1009.             Constrained, MoreHorizontal, FirstTime: boolean;
  1010.             offset, width: integer;
  1011.             rWidth: double;
  1012.     begin
  1013.         SaveLineWidth := LineWidth;
  1014.         p1 := event.where;
  1015.         start := p1;
  1016.         if OptionKeyDown then begin
  1017.                 case CurrentTool of
  1018.                     Brush, Pencil: 
  1019.                         GetForegroundColor(event);
  1020.                     Eraser: 
  1021.                         GetBackgroundColor(event);
  1022.                 end;
  1023.                 if (CurrentTool = Brush) or (CurrentTool = Eraser) then
  1024.                     exit(DoBrush);
  1025.             end;
  1026.         case CurrentTool of
  1027.             Pencil: 
  1028.                 LineWidth := 1;
  1029.             Brush, Eraser:  begin
  1030.                     if CurrentTool = Brush then
  1031.                         width := BrushWidth
  1032.                     else
  1033.                         width := 16;
  1034.                     LineWidth := round(width / info^.magnification);
  1035.                     if LineWidth < 1 then
  1036.                         LineWidth := 1;
  1037.                 end;
  1038.         end;
  1039.         with info^ do
  1040.             rWidth := (LineWidth - 1) * info^.magnification / 2.0;
  1041.             offset := round(rWidth * 1.00000001);  {ppc-bug}
  1042.         if CurrentTool <> Pencil then
  1043.             with p1 do begin
  1044.                     h := h - offset;
  1045.                     v := v - offset
  1046.                 end;
  1047.         Constrained := ShiftKeyDown;
  1048.         FirstTime := true;
  1049.         if CurrentTool = eraser then begin
  1050.                 SaveForegroundColor := ForegroundIndex;
  1051.                 SetForegroundColor(BackgroundIndex)
  1052.             end;
  1053.         repeat
  1054.             GetMouse(p2);
  1055.             if CurrentTool <> Pencil then
  1056.                 with p2 do begin
  1057.                         h := h - offset;
  1058.                         v := v - offset
  1059.                     end;
  1060.             if FirstTime then
  1061.                 if not EqualPt(p1, p2) then begin
  1062.                         MoreHorizontal := abs(p2.h - p1.h) >= abs(p2.v - p1.v);
  1063.                         FirstTime := false;
  1064.                     end;
  1065.             if Constrained then
  1066.                 if MoreHorizontal then
  1067.                     p2.v := p1.v
  1068.                 else
  1069.                     p2.h := p1.h;
  1070.             if CurrentTool = brush then
  1071.                 DrawObject(BrushObj, p1, p2)
  1072.             else
  1073.                 DrawObject(LineObj, p1, p2);
  1074.             p1 := p2;
  1075.         until not button;
  1076.         if CurrentTool = Eraser then
  1077.             SetForegroundColor(SaveForegroundColor);
  1078.         LineWidth := SaveLineWidth;
  1079.         WhatToUndo := UndoEdit;
  1080.     end;
  1081.  
  1082.  
  1083.     procedure DrawCharacter; {(ch: char)}
  1084.         var
  1085.             str: str255;
  1086.     begin
  1087.         if Info = NoInfo then begin
  1088.                 beep;
  1089.                 exit(DrawCharacter)
  1090.             end;
  1091.         if ch = cr then
  1092.             with InsertionPoint do begin
  1093.                     h := TextStart.h;
  1094.                     v := v + CurrentSize;
  1095.                     SetupUndo;
  1096.                     TextStr := '';
  1097.                     TextStart := InsertionPoint;
  1098.                     exit(DrawCharacter)
  1099.                 end;
  1100.         if ch = BackSpace then
  1101.             with InsertionPoint do begin
  1102.                     if length(TextStr) > 0 then begin
  1103.                             delete(TextStr, length(TextStr), 1);
  1104.                             DisplayText(true);
  1105.                         end;
  1106.                     exit(DrawCharacter)
  1107.                 end;
  1108.         str := ' '; {Needed for MPW}
  1109.         str[1] := ch;
  1110.         TextStr := Concat(TextStr, str);
  1111.         DisplayText(true);
  1112.     end;
  1113.  
  1114.  
  1115.     procedure DoText; {(loc: point)}
  1116.   {Handles text tool mouse clicks.}
  1117.         var
  1118.             value: extended;
  1119.             str: str255;
  1120.             isValue: boolean;
  1121.     begin
  1122.         if NoUndo then
  1123.             exit(DoText);
  1124.         ScreenToOffscreen(loc);
  1125.         with loc do begin
  1126.                 InsertionPoint.h := h;
  1127.                 InsertionPoint.v := v + 4;
  1128.             end;
  1129.         IsInsertionPoint := true;
  1130.         TextStart := InsertionPoint;
  1131.         TextStr := '';
  1132.         if OptionKeyDown then
  1133.             with info^ do begin
  1134.                     isValue := true;
  1135.                     if (PreviousTool = LineTool) and (nLengths > 0) then
  1136.                         value := plength^[mCount2]
  1137.                     else if (PreviousTool = AngleTool) and (nAngles > 0) then
  1138.                         value := orientation^[mCount2]
  1139.                     else if mCount > 0 then
  1140.                         if AreaM in Measurements then
  1141.                             value := mArea^[mCount2]
  1142.                         else if MeanM in Measurements then
  1143.                             value := mean^[mCount2]
  1144.                         else
  1145.                             isValue := false;
  1146.                     if isValue then begin
  1147.                             RealToString(value, 1, precision, str);
  1148.                             if mCount2 > 0 then
  1149.                                 mCount2 := mCount2 - 1;
  1150.                             DrawTextString(str, TextStart, TextJust);
  1151.                         end;
  1152.                 end;
  1153.         WhatToUndo := UndoEdit;
  1154.     end;
  1155.  
  1156.  
  1157.     procedure DoFill (event: EventRecord);
  1158.         var
  1159.             loc: point;
  1160.             MaskBits: BitMap;
  1161.             BitMapSize: LongInt;
  1162.             tPort: GrafPtr;
  1163.             trect: rect;
  1164.             SaveGDevice: GDHandle;
  1165.     begin
  1166.         ShowWatch;
  1167.         loc := event.where;
  1168.         ScreenToOffscreen(loc);
  1169.         with info^ do begin
  1170.                 tRect := PicRect;
  1171.                 with tRect do
  1172.                     if (right mod 16 <> 0) and not Has32BitQuickDraw then
  1173.                         right := (right div 16) * 16 + 16;  {Workaround for SeedCFill bug that results in  garbage along right edge.}
  1174.                 with MaskBits do begin
  1175.                         RowBytes := PixelsPerLine div 8 + 1;
  1176.                         if odd(RowBytes) then
  1177.                             RowBytes := RowBytes + 1;
  1178.                         bounds := tRect;
  1179.                         BitMapSize := rowBytes * nLines;
  1180.                         baseAddr := NewPtr(BitMapSize);
  1181.                         if baseAddr = nil then begin
  1182.                                 beep;
  1183.                                 exit(DoFill)
  1184.                             end;
  1185.                     end;
  1186.                 SaveGDevice := GetGDevice;
  1187.                 SetGDevice(osGDevice);
  1188.                 GetPort(tPort);
  1189.                 SetPort(GrafPtr(osPort));
  1190.                 pmForeColor(ForegroundIndex);
  1191.                 SeedCFill(BitMapHandle(osPort^.PortPixMap)^^, MaskBits, tRect, tRect, loc.h, loc.v, nil, 0);
  1192.                 CopyBits(MaskBits, BitMapHandle(osPort^.PortPixMap)^^, tRect, tRect, SrcOr, nil);
  1193.                 DisposePtr(MaskBits.baseAddr);
  1194.                 changes := true;
  1195.             end; {with}
  1196.         SetPort(tPort);
  1197.         SetGDevice(SaveGDevice);
  1198.         UpdatePicWindow;
  1199.         WhatToUndo := UndoEdit;
  1200.     end;
  1201.  
  1202.  
  1203.     procedure SetSprayCanSize;
  1204.         var
  1205.             TempSize: integer;
  1206.             Canceled: boolean;
  1207.     begin
  1208.         TempSize := GetInt('Spray can diameter in pixels(2-250):', SprayCanDiameter, Canceled);
  1209.         if Canceled then
  1210.             exit(SetSprayCanSize);
  1211.         if (TempSize > 1) and (TempSize <= 250) then begin
  1212.                 SprayCanDiameter := TempSize;
  1213.                 SprayCanRadius := SprayCanDiameter div 2;
  1214.                 SprayCanRadius2 := SprayCanRadius * SprayCanRadius
  1215.             end
  1216.         else
  1217.             beep;
  1218.     end;
  1219.  
  1220.  
  1221.     procedure SetBrushSize;
  1222.         var
  1223.             TempSize: integer;
  1224.             Canceled: boolean;
  1225.             i, ticks, x, y: LongInt;
  1226.             v: integer;
  1227.     begin
  1228.         TempSize := GetInt('Brush Size in pixels(1..99):', BrushWidth, Canceled);
  1229.         if Canceled then
  1230.             exit(SetBrushSize);
  1231.         if (TempSize > 0) and (TempSize < 100) then begin
  1232.                 BrushWidth := TempSize;
  1233.                 BrushHeight := BrushWidth
  1234.             end
  1235.         else
  1236.             beep;
  1237. {exit(SetBrushSize);}
  1238.     {Timer}
  1239.         x := 100;
  1240.         y := 100;
  1241.         ticks := TickCount;
  1242.         for i := 1 to 1000000 do
  1243.             v := MyGetPixel(x, y);
  1244.         ShowMessage(concat('ticks=', long2str(TickCount - ticks)));
  1245.     end;
  1246.  
  1247.  
  1248.     procedure SetLineWidth;
  1249.         var
  1250.             TempSize: integer;
  1251.             Canceled: boolean;
  1252.     begin
  1253.         TempSize := GetInt('Line Width in pixels(1..100):', LineWidth, Canceled);
  1254.         if Canceled then
  1255.             exit(SetLineWidth);
  1256.         if (TempSize > 0) and (TempSize <= 100) then begin
  1257.                 LineWidth := TempSize;
  1258.                 ShowLineWidth;
  1259.             end
  1260.         else
  1261.             beep;
  1262.     end;
  1263.  
  1264.  
  1265.     procedure FindWhatToCopy;
  1266.         var
  1267.             kind: integer;
  1268.             WhichWindow: WindowPtr;
  1269.     begin
  1270.         WhatToCopy := NothingToCopy;
  1271.         WhichWindow := FrontWindow;
  1272.         if WhichWindow = nil then
  1273.             exit(FindWhatToCopy);
  1274.         kind := WindowPeek(WhichWindow)^.WindowKind;
  1275.         if (CurrentTool = PickerTool) and (kind <> TextKind) then
  1276.             WhatToCopy := CopyColor
  1277.         else begin
  1278.                 if (kind = PicKind) and measuring and (not macro) then
  1279.                     kind := ResultsKind;
  1280.                 case kind of
  1281.                     PicKind: 
  1282.                         with info^, info^.RoiRect do
  1283.                             if RoiShowing and (left >= 0) and (top >= 0) and (right <= PicRect.right) and (bottom <= PicRect.bottom) then
  1284.                                 WhatToCopy := CopySelection;
  1285.                     HistoKind: 
  1286.                         WhatToCopy := CopyHistogram;
  1287.                     ProfilePlotKind: 
  1288.                         WhatToCopy := CopyPlot;
  1289.                     CalibrationPlotKind: 
  1290.                         WhatToCopy := CopyCalibrationPlot;
  1291.                     LUTKind: 
  1292.                         if info <> NoInfo then
  1293.                             WhatToCopy := CopyCLUT;
  1294.                     MapKind: 
  1295.                         if info <> NoInfo then
  1296.                             WhatToCopy := CopyGrayMap;
  1297.                     ToolKind: 
  1298.                         WhatToCopy := CopyTools;
  1299.                     TextKind:  begin
  1300.                             TextInfo := TextInfoPtr(WindowPeek(WhichWindow)^.RefCon);
  1301.                             if TextInfo <> nil then
  1302.                                 with TextInfo^.TextTE^^ do
  1303.                                     if selEnd > selStart then
  1304.                                         WhatToCopy := CopyText;
  1305.                         end;
  1306.                     InfoKind, ResultsKind: 
  1307.                         if mCount > 0 then
  1308.                             WhatToCopy := CopyMeasurements;
  1309.                     otherwise
  1310.                 end;
  1311.             end;
  1312.     end;
  1313.  
  1314.  
  1315.     procedure UpdateEditMenu;
  1316.         var
  1317.             DimUndo, ShowItems: boolean;
  1318.             str: str255;
  1319.             i: integer;
  1320.     begin
  1321.         with info^ do begin
  1322.                 if CurrentKind < 0 then begin   {DA is active, so activate Edit menu.}
  1323.                         SetMenuItemText(EditMenuH, UndoItem, 'Undo');
  1324.                         SetMenuItemText(EditMenuH, CutItem, 'Cut');
  1325.                         SetMenuItemText(EditMenuH, CopyItem, 'Copy');
  1326.                         SetMenuItem(EditMenuH, UndoItem, true);
  1327.                         for i := CutItem to ClearItem do
  1328.                             SetMenuItem(EditMenuH, i, true);
  1329.                         exit(UpdateEditMenu);
  1330.                     end;
  1331.                 if not (WhatToUndo in [UndoLUT, UndoMeasurement, UndoPoint]) and ((info = NoInfo) or (PixMapSize <> CurrentUndoSize)) then
  1332.                     WhatToUndo := NothingToUndo;
  1333.                 DimUndo := WhatToUndo = NothingToUndo;
  1334.                 SetMenuItem(EditMenuH, UndoItem, not DimUndo);
  1335.                 if DimUndo then
  1336.                     SetMenuItemText(EditMenuH, UndoItem, 'Undo');
  1337.                 case WhatToUndo of
  1338.                     UndoEdit: 
  1339.                         str := 'Editing';
  1340.                     UndoFlip: 
  1341.                         str := 'Flip';
  1342.                     UndoRotate: 
  1343.                         str := 'Rotate';
  1344.                     UndoFilter: 
  1345.                         str := 'Filter';
  1346.                     UndoPaste: 
  1347.                         str := 'Paste';
  1348.                     UndoMeasurement, UndoPoint: 
  1349.                         str := 'Measurement';
  1350.                     UndoTransform: 
  1351.                         str := 'Transformation';
  1352.                     UndoClear: 
  1353.                         str := 'Clear';
  1354.                     UndoZoom: 
  1355.                         str := 'Zoom';
  1356.                     UndoOutline: 
  1357.                         str := 'Outline';
  1358.                     UndoSliceDelete, UndoFirstSliceDelete: 
  1359.                         str := 'Delete Slice';
  1360.                     UndoLUT: 
  1361.                         str := 'LUT Change';
  1362.                     otherwise
  1363.                         str := '';
  1364.                 end;
  1365.                 SetMenuItemText(EditMenuH, UndoItem, concat('Undo ', str));
  1366.                 FindWhatToCopy;
  1367.                 if WhatToCopy = CopySelection then
  1368.                     str := 'Cut Selection'
  1369.                 else
  1370.                     str := 'Cut';
  1371.                 SetMenuItemText(EditMenuH, CutItem, str);
  1372.                 SetMenuItem(EditMenuH, CutItem, (WhatToCopy = CopySelection) or (WhatToCopy = CopyText));
  1373.                 case WhatToCopy of
  1374.                     NothingToCopy, CopyText: 
  1375.                         str := '';
  1376.                     CopySelection: 
  1377.                         str := 'Selection';
  1378.                     CopyCLUT: 
  1379.                         str := 'LUT';
  1380.                     CopyGrayMap: 
  1381.                         str := 'Gray Map';
  1382.                     CopyTools: 
  1383.                         str := 'Tools';
  1384.                     CopyPlot: 
  1385.                         str := 'Plot';
  1386.                     CopyCalibrationPlot: 
  1387.                         str := 'Calibration Plot';
  1388.                     CopyHistogram: 
  1389.                         str := 'Histogram';
  1390.                     CopyMeasurements: 
  1391.                         str := 'Measurements';
  1392.                     CopyColor: 
  1393.                         str := 'Color';
  1394.                 end;
  1395.                 SetMenuItemText(EditMenuH, CopyItem, concat('Copy ', str));
  1396.                 SetMenuItem(EditMenuH, CopyItem, WhatToCopy <> NothingToCopy);
  1397.                 SetMenuItem(EditMenuH, ClearItem, (WhatToCopy = CopySelection) or (WhatToCopy = CopyText));
  1398.                 ShowItems := (WhatsOnClip <> NothingOnClip) or (OldScrapCount <> GetScrapCount);
  1399.                 SetMenuItem(EditMenuH, PasteItem, ShowItems);
  1400.                 SetMenuItem(EditMenuH, ShowClipboardItem, ShowItems);
  1401.                 ShowItems := info <> NoInfo;
  1402.                 if CurrentKind = TextKind then
  1403.                     SetMenuItemText(EditMenuH, FillItem, 'Find…')
  1404.                 else
  1405.                     SetMenuItemText(EditMenuH, FillItem, 'Fill');
  1406.                 SetMenuItem(EditMenuH, FillItem, ShowItems or (CurrentKind = TextKind));
  1407.                 SetMenuItem(EditMenuH, InvertItem, ShowItems);
  1408.                 SetMenuItem(EditMenuH, DrawBoundaryItem, ShowItems);
  1409.                 SetMenuItem(EditMenuH, DrawScaleItem, ShowItems);
  1410.                 if (RoiShowing and EqualRect(RoiRect, PicRect)) and (CurrentKind <> TextKind) then
  1411.                     SetMenuItemText(EditMenuH, SelectAllItem, 'Deselect All')
  1412.                 else
  1413.                     SetMenuItemText(EditMenuH, SelectAllItem, 'Select All');
  1414.                 SetMenuItem(EditMenuH, SelectAllItem, ShowItems or (CurrentKind = TextKind));
  1415.                 SetMenuItem(EditMenuH, DeselectItem, ShowItems and RoiShowing);
  1416.                 SetMenuItem(EditMenuH, ScaleAndRotateItem, ShowItems);
  1417.                 for i := RotateLeftItem to FlipHorizontalItem do
  1418.                     SetMenuItem(EditMenuH, i, ShowItems);
  1419.                 SetMenuItem(EditMenuH, UnZoomItem, ShowItems and ((magnification <> 1.0) or ScaleToFitWindow));
  1420.             end; {with}
  1421.     end;
  1422.  
  1423.  
  1424.     procedure ZoomOut;
  1425.         var
  1426.             Width, Height, divisor, NewWidth, NewHeight: integer;
  1427.             OldMagnification, xratio, yratio: extended;
  1428.     begin
  1429.         with Info^ do begin
  1430.                 if magnification < 2.0 then begin
  1431.                         beep;
  1432.                         exit(ZoomOut)
  1433.                     end;
  1434.                 OldMagnification := magnification;
  1435.                 if magnification = 2.0 then begin
  1436.                         magnification := 1.0;
  1437.                         divisor := 4
  1438.                     end
  1439.                 else if magnification = 3.0 then begin
  1440.                         magnification := 2.0;
  1441.                         divisor := 6
  1442.                     end
  1443.                 else if magnification = 4.0 then begin
  1444.                         magnification := 3.0;
  1445.                         divisor := 8
  1446.                     end
  1447.                 else begin
  1448.                         magnification := magnification / 2.0;
  1449.                         divisor := 4
  1450.                     end;
  1451.                 if EqualRect(SrcRect, PicRect) then begin {Make window smaller}
  1452.                         NewWidth := trunc(PicRect.right * magnification);
  1453.                         NewHeight := trunc(PicRect.bottom * magnification);
  1454.                         SizeWindow(wptr, NewWidth, NewHeight, true);
  1455.                         wrect.right := NewWidth;
  1456.                         wrect.bottom := NewHeight;
  1457.                         SrcRect := PicRect;
  1458.                         UpdateTitleBar;
  1459.                         UpdatePicWindow;
  1460.                         DrawMyGrowIcon(wptr);
  1461.                         exit(ZoomOut);
  1462.                     end;
  1463.                 if ((wrect.right > PicRect.right) or (wrect.bottom > PicRect.bottom)) then begin
  1464.                         xratio := wrect.right / PicRect.right;
  1465.                         yratio := wrect.bottom / PicRect.bottom;
  1466.                         if (xratio <> yratio) or ((xratio - trunc(xratio)) <> 0.0) then begin
  1467.                                 UnZoom;
  1468.                                 Exit(ZoomOut)
  1469.                             end;
  1470.                         SrcRect := PicRect;
  1471.                         Magnification := xratio;
  1472.                         UpdateTitleBar;
  1473.                         UpdatePicWindow;
  1474.                         DrawMyGrowIcon(wptr);
  1475.                         Exit(ZoomOut)
  1476.                     end;
  1477.             end; {with}
  1478.         with Info^.SrcRect, info^ do begin
  1479.                 if magnification = 1.0 then begin
  1480.                         width := wrect.right;
  1481.                         height := wrect.bottom;
  1482.                     end
  1483.                 else begin
  1484.                         width := round((right - left) * OldMagnification / Magnification);
  1485.                         height := round((bottom - top) * OldMagnification / Magnification);
  1486.                     end;
  1487.                 left := left - (width div divisor);
  1488.                 if left < 0 then
  1489.                     left := 0;
  1490.                 if (left + width) > Info^.PicRect.right then
  1491.                     left := Info^.PicRect.right - width;
  1492.                 top := top - (height div divisor);
  1493.                 if top < 0 then
  1494.                     top := 0;
  1495.                 if (top + height) > Info^.PicRect.bottom then
  1496.                     top := Info^.picRect.bottom - height;
  1497.                 right := left + width;
  1498.                 bottom := top + height;
  1499.                 RoiShowing := false;
  1500.                 UpdatePicWindow;
  1501.                 DrawMyGrowIcon(wptr);
  1502.                 UpdateTitleBar;
  1503.             end;
  1504.         ShowRoi;
  1505.     end;
  1506.  
  1507.  
  1508.     procedure DoGrow; {(WhichWindow: WindowPtr; event: EventRecord)}
  1509.         var
  1510.             NewSize: LongInt;
  1511.             trect, WinRect, SizeRect: rect;
  1512.             kind: integer;
  1513.             WasDigitizing: boolean;
  1514.             ZoomCenterH, ZoomCenterV, width, height: extended;
  1515.     begin
  1516.         kind := WindowPeek(WhichWindow)^.WindowKind;
  1517.         if kind = PicKind then
  1518.             with info^, SizeRect do begin
  1519.                     if ScaleToFitWindow then
  1520.                         SizeRect := qd.ScreenBits.bounds
  1521.                     else begin
  1522.                             right := PicRect.right + 1;
  1523.                             bottom := PicRect.bottom + 1;
  1524.                             if magnification > 1.0 then begin
  1525.                                     right := round(right * magnification);
  1526.                                     bottom := round(bottom * magnification);
  1527.                                 end;
  1528.                             left := 32;
  1529.                             top := 32;
  1530.                             if left > right then
  1531.                                 left := right;
  1532.                             if top > bottom then
  1533.                                 top := bottom;
  1534.                         end
  1535.                 end
  1536.         else
  1537.             SetRect(SizeRect, 64, 48, 2048, 2048);
  1538.         NewSize := GrowWindow(WhichWindow, event.where, SizeRect);
  1539.         if newSize = 0 then
  1540.             exit(DoGrow);
  1541.         if kind = PicKind then
  1542.             with Info^ do begin
  1543.                     SetPort(wptr);
  1544.                     WasDigitizing := digitizing;
  1545.                     StopDigitizing;
  1546.                     InvalRect(wrect);
  1547.                     with trect do begin
  1548.                             top := 0;
  1549.                             left := 0;
  1550.                             right := LoWrd(NewSize);
  1551.                             bottom := HiWrd(NewSize);
  1552.                         end;
  1553.                     if ScaleToFitWindow then begin
  1554.                             ScaleImageWindow(trect);
  1555.                             wrect := trect;
  1556.                         end
  1557.                     else begin
  1558.                             if trect.right > PicRect.right * magnification then
  1559.                                 trect.right := trunc(PicRect.right * magnification);
  1560.                             if trect.bottom > PicRect.bottom * magnification then
  1561.                                 trect.bottom := trunc(PicRect.bottom * magnification);
  1562.                             wrect := trect;
  1563.                             with SrcRect do begin
  1564.                                     ZoomCenterH := left + (wrect.right / 2.0) / magnification;
  1565.                                     ZoomCenterV := top + (wrect.bottom / 2.0) / magnification;
  1566.                                     width := wrect.right / magnification;
  1567.                                     height := wrect.bottom / magnification;
  1568.                                     left := round(ZoomCenterH - width / 2.0);
  1569.                                     if left < 0 then
  1570.                                         left := 0;
  1571.                                     if (left + width) > PicRect.right then
  1572.                                         left := round(PicRect.right - width);
  1573.                                     top := round(ZoomCenterV - height / 2.0);
  1574.                                     if top < 0 then
  1575.                                         top := 0;
  1576.                                     if (top + height) > PicRect.bottom then
  1577.                                         top := round(picRect.bottom - height);
  1578.                                     right := round(left + width);
  1579.                                     bottom := round(top + height);
  1580.                                     wrect.right := trunc((right - left) * magnification);
  1581.                                     wrect.bottom := trunc((bottom - top) * magnification);
  1582.                                 end;
  1583.                             savewrect := wrect;
  1584.                         end;
  1585.                     SizeWindow(WhichWindow, wrect.right, wrect.bottom, true);
  1586.                     WindowState := NormalWindow;
  1587.                     if WasDigitizing then
  1588.                         StartDigitizing;
  1589.                     exit(DoGrow)
  1590.                 end; {with info^}
  1591.         if WhichWindow = PlotWindow then begin
  1592.                 PlotWidth := LoWrd(NewSize);
  1593.                 PlotHeight := HiWrd(NewSize);
  1594.                 SetPort(PlotWindow);
  1595.                 SizeWindow(PlotWindow, PlotWidth, Plotheight, true);
  1596.                 InvalRect(PlotWindow^.PortRect);
  1597.                 exit(DoGrow)
  1598.             end;
  1599.         if (kind = TextKind) then begin
  1600.                 TextInfo := TextInfoPtr(WindowPeek(WhichWindow)^.RefCon);
  1601.                 GrowTextWindow(NewSize);
  1602.                 exit(DoGrow)
  1603.             end;
  1604.         if WhichWindow = ResultsWindow then begin
  1605.                 ResultsWidth := LoWrd(NewSize);
  1606.                 ResultsHeight := HiWrd(NewSize);
  1607.                 SetPort(ResultsWindow);
  1608.                 with ResultsWindow^.PortRect do
  1609.                     SetRect(tRect, right - 12, bottom - 12, right, bottom);
  1610.                 EraseRect(trect); {Erase Grow Box}
  1611.                 SizeWindow(ResultsWindow, ResultsWidth, ResultsHeight, true);
  1612.                 MoveControl(hScrollBar, -1, ResultsHeight - ScrollBarWidth);
  1613.                 MoveControl(vScrollBar, ResultsWidth - ScrollBarWidth, -1);
  1614.                 SizeControl(hScrollBar, ResultsWidth - 13, ScrollBarWidth + 1);
  1615.                 SizeControl(vScrollBar, ScrollBarWidth + 1, ResultsHeight - 13);
  1616.                 InvalRect(ResultsWindow^.PortRect);
  1617.                 with ListTE^^.viewRect do begin
  1618.                         right := left + ResultsWidth - ScrollBarWidth - 4;
  1619.                         bottom := top + ResultsHeight - ScrollBarWidth;
  1620.                     end;
  1621.                 UpdateResultsScrollBars;
  1622.                 ScrollResultsText;
  1623.             end;
  1624.     end;
  1625.  
  1626.  
  1627.     procedure ZoomIn; {(event: EventRecord)}
  1628.         var
  1629.             width, height, OldMagnification: extended;
  1630.             PicCenterH, PicCenterV, NewWidth, NewHeight: integer;
  1631.             trect: rect;
  1632.     begin
  1633.         if Info = NoInfo then begin
  1634.                 beep;
  1635.                 exit(ZoomIn)
  1636.             end;
  1637.         if Info^.ScaleToFitWindow then begin
  1638.                 PutError('The magnifying glass does not work in "Scale to Fit Window" mode.');
  1639.                 exit(ZoomIn)
  1640.             end;
  1641.         if BitAnd(Event.modifiers, OptionKey) = OptionKey then begin
  1642.                 ZoomOut;
  1643.                 WhatToUndo := NothingToUndo;
  1644.                 exit(ZoomIn)
  1645.             end;
  1646.         with Info^ do begin
  1647.                 OldMagnification := magnification;
  1648.                 if magnification = 1.0 then
  1649.                     magnification := 2.0
  1650.                 else if magnification = 2.0 then
  1651.                     magnification := 3.0
  1652.                 else if magnification = 3.0 then
  1653.                     magnification := 4.0
  1654.                 else begin
  1655.                         magnification := magnification * 2.0;
  1656.                         if magnification > 64.0 then begin
  1657.                                 magnification := 64.0;
  1658.                                 exit(ZoomIn)
  1659.                             end;
  1660.                     end;
  1661.                 if (WindowState = NormalWindow) and EqualRect(SrcRect, PicRect) then {Make window bigger?}
  1662.                     with trect do begin
  1663.                             NewWidth := trunc(PicRect.right * magnification);
  1664.                             NewHeight := trunc(PicRect.bottom * magnification);
  1665.                             if NewWidth <= 640 then begin
  1666.                                     GetWindowRect(wptr, trect);
  1667.                                     if ((left + NewWidth) <= ScreenWidth) and ((top + NewHeight) <= ScreenHeight) then begin
  1668.                                             SizeWindow(wptr, NewWidth, NewHeight, true);
  1669.                                             wrect.right := NewWidth;
  1670.                                             wrect.bottom := NewHeight;
  1671.                                         end;
  1672.                                 end;
  1673.                         end;
  1674.             end; {with}
  1675.         with Info^.SrcRect, Info^ do begin
  1676.                 PicCenterH := left + round(event.where.h / OldMagnification);
  1677.                 PicCenterV := top + round(event.where.v / OldMagnification);
  1678.                 width := wrect.right / magnification;
  1679.                 height := wrect.bottom / magnification;
  1680.                 left := PicCenterH - round(width / 2.0);
  1681.                 if left < 0 then
  1682.                     left := 0;
  1683.                 if (left + width) > PicRect.right then
  1684.                     left := PicRect.right - round(width);
  1685.                 top := PicCenterV - round(height / 2.0);
  1686.                 if top < 0 then
  1687.                     top := 0;
  1688.                 if (top + height) > PicRect.bottom then
  1689.                     top := picRect.bottom - round(height);
  1690.                 right := left + round(width);
  1691.                 bottom := top + round(height);
  1692.                 wrect.right := trunc((right - left) * magnification);
  1693.                 wrect.bottom := trunc((bottom - top) * magnification);
  1694.                 SizeWindow(wptr, wrect.right, wrect.bottom, true);
  1695.                 RoiShowing := false;
  1696.                 UpdatePicWindow;
  1697.                 DrawMyGrowIcon(wptr);
  1698.                 UpdateTitleBar;
  1699.                 WhatToUndo := UndoZoom;
  1700.                 ShowRoi;
  1701.             end; {with}
  1702.     end;
  1703.  
  1704.  
  1705.     procedure SynchScroll;
  1706.         var
  1707.             n: integer;
  1708.             TempInfo, SaveInfo: InfoPtr;
  1709.     begin
  1710.         SaveInfo := info;
  1711.         if allsamesize then
  1712.             for n := 1 to nPics do begin
  1713.                     TempInfo := pointer(WindowPeek(PicWindow[n])^.RefCon);
  1714.                     TempInfo^.SrcRect := info^.SrcRect;
  1715.                     TempInfo^.magnification := Info^.magnification;
  1716.                     info := TempInfo;
  1717.                     UpdatePicWindow;
  1718.                     Info := SaveInfo;
  1719.                 end
  1720.         else
  1721.             PutError('Synchronized scrolling requires all images and all windows to be the same size.');
  1722.     end;
  1723.  
  1724.  
  1725.     procedure Scroll; {(event: EventRecord)}
  1726.         var
  1727.             hstart, vstart, DeltaH, DeltaV, width, height: integer;
  1728.             loc: point;
  1729.             SaveSR: rect;
  1730.             WasDigitizing: boolean;
  1731.     begin
  1732.         with info^ do begin
  1733.                 if ScaleToFitWindow then begin
  1734.                         PutError('Scrolling does not work in "Scale to Fit Window" mode.');
  1735.                         exit(Scroll)
  1736.                     end;
  1737.                 WasDigitizing := digitizing;
  1738.                 StopDigitizing;
  1739.                 with event.where do begin
  1740.                         hstart := h;
  1741.                         vstart := v
  1742.                     end;
  1743.                 with SrcRect do begin
  1744.                         width := right - left;
  1745.                         height := bottom - top
  1746.                     end;
  1747.                 SaveSR := SrcRect;
  1748.                 while StillDown do begin
  1749.                         GetMouse(loc);
  1750.                         DeltaH := hstart - loc.h;
  1751.                         DeltaV := vstart - loc.v;
  1752.                         with SrcRect do begin
  1753.                                 left := SaveSR.left + DeltaH;
  1754.                                 if left < 0 then
  1755.                                     left := 0;
  1756.                                 if (left + width) > PicRect.right then
  1757.                                     left := PicRect.right - width;
  1758.                                 right := left + width;
  1759.                                 top := SaveSR.top + DeltaV;
  1760.                                 if top < 0 then
  1761.                                     top := 0;
  1762.                                 if (top + height) > PicRect.bottom then
  1763.                                     top := PicRect.bottom - height;
  1764.                                 bottom := top + height;
  1765.                             end;
  1766.                         UpdatePicWindow;
  1767.                         DrawMyGrowIcon(wptr);
  1768.                     end;
  1769.                 WhatToUndo := NothingToUndo;
  1770.                 ShowRoi;
  1771.                 if OptionKeyDown and (nPics > 1) then
  1772.                     SynchScroll;
  1773.                 if WasDigitizing then
  1774.                     StartDigitizing;
  1775.             end; {with info^}
  1776.     end;
  1777.  
  1778.  
  1779.     procedure ConverToSystemClipboard;
  1780.     {Converts local clipboard to system-wide clipboard}
  1781.     {when quitting or switching to other programs.}
  1782.     var
  1783.         PicH: PicHandle;
  1784.         err: LongInt;
  1785.         saveClipRgn: RgnHandle;
  1786.     begin
  1787.         PicH := nil;
  1788.         if ((WhatsOnClip = RectPic) or (WhatsOnClip = CameraPic)) and (ClipBuf <> nil) and not ClipboardConverted then
  1789.             with ClipBufInfo^ do begin
  1790.                 ShowWatch;
  1791.                 SetPort(GrafPtr(osPort));
  1792.                 saveClipRgn := NewRgn;
  1793.                 GetClip(saveClipRgn);
  1794.                 ClipRect(RoiRect);
  1795.                 LoadLUT(ctable);  {Switch to original LUT}
  1796.                 RGBForeColor(BlackRGB);
  1797.                 RGBBackColor(WhiteRGB);
  1798.                 PicH := OpenPicture(RoiRect);
  1799.                 with osPort^ do
  1800.                     CopyBits(BitMapHandle(portPixMap)^^, BitMapHandle(portPixMap)^^, RoiRect, RoiRect, SrcCopy, nil);
  1801.                 ClosePicture;
  1802.                 if info <> NoInfo then
  1803.                     LoadLUT(info^.ctable); {Restore LUT}
  1804.                 if (PicH <> nil) or ClipTextInBuffer then begin
  1805.                         err := ZeroScrap;
  1806.                         if err = NoErr then begin
  1807.                             if PicH <> nil then begin
  1808.                                 hlock(handle(PicH));
  1809.                                 err := PutScrap(GetHandleSize(handle(PicH)), 'PICT', handle(PicH)^);
  1810.                                 hunlock(handle(PicH));
  1811.                                 DisposeHandle(handle(PicH));
  1812.                             end;
  1813.                             if (err = noErr) and ClipTextInBuffer then
  1814.                                 err := PutScrap(TextBufSize, 'TEXT', ptr(TextBufP));
  1815.                         end; {if err=NoErr}
  1816.                     end;
  1817.                 ClipboardConverted := true;
  1818.                 SetClip(saveClipRgn);
  1819.                 DisposeRgn(saveClipRgn);
  1820.             end; {with}
  1821.     end;
  1822.  
  1823.  
  1824.     procedure SetupOperation; {(item: integer)}
  1825.         var
  1826.             AutoSelectAll: boolean;
  1827.     begin
  1828.         if NotinBounds then
  1829.             exit(SetupOperation);
  1830.         if item = DrawBoundaryItem then
  1831.             if NoSelection then
  1832.                 exit(SetupOperation);
  1833.         if item = InvertItem then
  1834.             if not CheckCalibration then
  1835.                 exit(SetupOperation);
  1836.         StopDigitizing;
  1837.         AutoSelectAll := not Info^.RoiShowing;
  1838.         if AutoSelectAll then
  1839.             SelectAll(true);
  1840.         SetupUndo;
  1841.         WhatToUndo := UndoEdit;
  1842.         case Item of
  1843.             FillItem:  begin
  1844.                     CurrentOp := PaintOp;
  1845.                     OpPending := true
  1846.                 end;
  1847.             InvertItem:  begin
  1848.                     CurrentOp := InvertOp;
  1849.                     OpPending := true
  1850.                 end;
  1851.             DrawBoundaryItem:  begin
  1852.                     CurrentOp := FrameOp;
  1853.                     OpPending := true
  1854.                 end;
  1855.         end;
  1856.         if AutoSelectAll then
  1857.             KillRoi;
  1858.         RoiUpdateTime := 0; {Forces outline to be redrawn in scale-to-fit mode.}
  1859.     end;
  1860.  
  1861.  
  1862.     procedure DoUndo;
  1863.         var
  1864.             aok: boolean;
  1865.     begin
  1866.         case WhatToUndo of
  1867.             UndoMeasurement: 
  1868.                 UndoLastMeasurement(true);
  1869.             UndoPoint:  begin
  1870.                     Undo;
  1871.                     UpdatePicWindow;
  1872.                     UndoLastMeasurement(true);
  1873.                     WhatToUndo := NothingToUndo;
  1874.                 end;
  1875.             UndoZoom:  begin
  1876.                     ZoomOut;
  1877.                     if info^.magnification < 2 then
  1878.                         WhatToUndo := NothingToUndo;
  1879.                 end;
  1880.             UndoOutLine:  begin
  1881.                     undo;
  1882.                     if WandAutoMeasure then
  1883.                         UndoLastMeasurement(true);
  1884.                     WhatToUndo := NothingToUndo;
  1885.                     UpdatePicWindow;
  1886.                 end;
  1887.             UndoSliceDelete, UndoFirstSliceDelete: 
  1888.                 if info^.StackInfo <> nil then
  1889.                     with info^.StackInfo^ do begin
  1890.                             if WhatToUndo = UndoFirstSliceDelete then
  1891.                                 CurrentSlice := 0;
  1892.                             aok := AddSlice(false);
  1893.                             if aok then begin
  1894.                                     Undo;
  1895.                                     UpdatePicWindow;
  1896.                                 end
  1897.                             else if CurrentSlice = 0 then
  1898.                                 CurrentSlice := 1;
  1899.                         end;
  1900.             UndoLUT:  begin
  1901.                     UndoLutChange;
  1902.                     DrawMap;
  1903.                     DensitySlicing := false;
  1904.                 end;
  1905.             otherwise begin
  1906.                     if UndoFromClip then
  1907.                         OpPending := false;
  1908.                     if not OpPending then
  1909.                         undo;
  1910.                     WhatToUndo := NothingToUndo;
  1911.                     if IsInsertionPoint then begin
  1912.                             InsertionPoint := TextStart;
  1913.                             TextStr := '';
  1914.                         end;
  1915.                     UpdatePicWindow;
  1916.                     if OpPending and (CurrentOp = PasteOp) then begin
  1917.                             OpPending := false;
  1918.                             KillRoi;
  1919.                         end;
  1920.                     OpPending := false;
  1921.                 end;
  1922.         end; {case}
  1923.     end;
  1924.  
  1925.  
  1926.  
  1927. end.